package com.alogic.pipeline.impl;

import com.alogic.pipeline.PipelineListener;
import com.alogic.pipeline.PipelineStage;
import com.alogic.terminal.Resolver;
import com.alogic.terminal.Terminal;
import com.alogic.terminal.xscript.XShell;
import com.alogic.xscript.Logiclet;
import com.alogic.xscript.LogicletContext;
import com.alogic.xscript.Script;
import com.alogic.xscript.doc.XsObject;
import com.alogic.xscript.doc.json.JsonObject;
import com.anysoft.util.Properties;
import com.anysoft.util.PropertiesConstants;
import com.anysoft.util.XmlElementProperties;
import com.anysoft.util.XmlTools;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Element;

import java.util.HashMap;

/**
 * 通过本地指令来允许作业
 *
 * @since 1.6.14.16 [20210816 duanyy] <br>
 */
public class LocalComamnd extends PipelineStage.Base {
    protected Logiclet onLog = null;
    protected Logiclet onCommand = null;

    @Override
    public void run(String jobId, Properties ctx, PipelineListener listener) {
        if (onCommand != null){
            LogicletContext logicletContext = new LogicletContext(ctx);
            try {
                XsObject doc = new JsonObject("root",new HashMap<String,Object>());
                onCommand.execute(doc,doc, logicletContext, null);
                String cmd = PropertiesConstants.getString(logicletContext,"$cmd",null);
                if (StringUtils.isNotEmpty(cmd)) {
                    execute(cmd, ctx);
                }else{
                    String message = "Cmd is not found,ingored.";
                    log(message,logicletContext);
                    ctx.SetValue("$state", "ok");
                    ctx.SetValue("$stateMessage", message);
                }
            }catch (Exception ex){
                log(ex.getMessage(),logicletContext);
                ctx.SetValue("$state", "failed");
                ctx.SetValue("$stateMessage", "指令执行错误.");
            }
        }else{
            String message = "Cmd is not found,ingored.";
            log(message,ctx);
            ctx.SetValue("$state", "ok");
            ctx.SetValue("$stateMessage", message);
        }
    }

    @Override
    public void configure(Properties p) {
        super.configure(p);
    }

    @Override
    public void configure(Element e, Properties p) {
        XmlElementProperties props = new XmlElementProperties(e, p);
        configure(props);
        loadPairs(e, p);
        Element elem = XmlTools.getFirstElementByPath(e, "on-log");
        if (elem != null) {
            onLog = Script.create(elem, props);
        }

        elem = XmlTools.getFirstElementByPath(e, "on-command");
        if (elem != null) {
            onCommand = Script.create(elem, props);
        }
    }

    protected void execute(String cmd, final Properties ctx) {
        Terminal t = null;
        XShell.TerminalFactory f = new XShell.TerminalFactory();
        try {
            t = f.newInstance("local");
        } catch (Exception ex) {
            LOG.error(String.format("Can not create Local terminal"));
        }

        if (t != null) {
            try {
                t.connect();

                Resolver resolver = new Resolver() {
                    @Override
                    public Object resolveBegin(String cmd) {
                        log(cmd, ctx);
                        return cmd;
                    }
                    @Override
                    public void resolveLine(Object cookies, String content) {
                        log(content, ctx);
                    }
                    @Override
                    public void resolveEnd(Object cookies) {
                    }
                };

                boolean ok = true;
                if (t.exec(resolver,cmd) != 0) {
                    ok = false;
                    ctx.SetValue("$state", "failed");
                    ctx.SetValue("$stateMessage", "failed");
                }
                if (ok) {
                    ctx.SetValue("$state", "ok");
                    ctx.SetValue("$stateMessage", "done");
                }
            } finally {
                t.disconnect();
            }
        }

    }

    protected void log(String line, Properties ctx) {
        if (onLog != null) {
            LogicletContext logicletContext = new LogicletContext(ctx);
            try {
                XsObject doc = new JsonObject("root", new HashMap<String, Object>());
                ctx.SetValue("$line", line);
                onLog.execute(doc, doc, logicletContext, null);
            } catch (Exception ex) {
                ctx.SetValue("$state", "failed");
                ctx.SetValue("$stateMessage", ex.getMessage());
            }
        }
    }
}
